#include "breadcrumbssync.h"
#include "configuration.h"
#include "oauthmanager.h"

#include "controls/ftlabel.h"
#include "controls/fttextarea.h"
#include "controls/ftpushbutton.h"
#include "controls/ftvboxlayout.h"
#include "controls/fthboxlayout.h"
#include "controls/ftcombobox.h"
#include "controls/ftmessagebox.h"
#include "controls/ftcheckbox.h"
#include "controls/filebrowser.h"

#include "workers/workersavegpx.h"
#include "workers/workerloadgpx.h"

QMap<QString, QString> BreadcrumbsSync::list_activities;
QMap<QString, QMap<QString,QString> > BreadcrumbsSync::list_bundles;
bool BreadcrumbsSync::loaded = false;

BreadcrumbsSync::BreadcrumbsSync() :
    RotatingWidget()
{
    track = NULL;
    downloadedTrack = NULL;
    oauth = NULL;

    pages = new QStackedWidget();
    buildNotConfigured();
    buildUpload();
    buildDownload();
    _currentMode = not_initialized;
}

BreadcrumbsSync::~BreadcrumbsSync()
{
    if (oauth != NULL )
        delete oauth;

    if ( downloadedTrack != NULL )
        delete downloadedTrack;

    foreach (searched_track* trk, download_fetched)
        delete trk;
}

GPS_track* BreadcrumbsSync::fetchDownloadedTrack()
{
    GPS_track* tmp = downloadedTrack;
    downloadedTrack = NULL;
    return tmp;
}

BreadcrumbsSync::mode BreadcrumbsSync::currentMode() const
{
    return _currentMode;
}

void BreadcrumbsSync::buildNotConfigured()
{
    notConfiguredLabel = new FTTextArea(tr("Access to www.gobreadcrumbs.com must be\nactivated first.\nPlease check the configuration."));
    pages->addWidget( notConfiguredLabel );
}

void BreadcrumbsSync::buildDownload()
{
    downloadPage = new QWidget();
    pages->addWidget( downloadPage );

    download_searchButton = new FTPushButton( tr("Search...") );
    connect( download_searchButton, SIGNAL(clicked()),
             this, SLOT(download_searchTracks()) );

    download_fetchButton = new FTPushButton( tr("Fetch track...") );
    connect( download_fetchButton, SIGNAL(clicked()),
             this, SLOT(download_fetchTrack()) );
    download_fetchButton->setEnabled( false );

    download_activityLabel = new FTLabel( tr("Activity:") );
    download_reloadButton = new FTPushButton( tr("Reload") );
    connect( download_reloadButton, SIGNAL(clicked()),
             this, SLOT(forceReload()) );

    download_activityCombo = new FTComboBox();

    download_fetchedCombo = new FTComboBox();
    connect(download_fetchedCombo, SIGNAL(selectedIndex(int)),
            this, SLOT(download_displayTrack()) );

    download_numTracksLabel = new FTLabel("Download up to:");
    download_numTracksCombo = new FTComboBox();
    download_numTracksCombo->addItem(10, tr("ten tracks"));
    download_numTracksCombo->addItem(50, tr("fifty tracks"));
    download_numTracksCombo->addItem(100, tr("hundred tracks"));
    download_numTracksCombo->selectFirst();

    download_distanceLabel = new FTLabel("Distance up to:");
    download_distanceCombo = new FTComboBox();
    download_distanceCombo->addItem(1, tr("1km"));
    download_distanceCombo->addItem(10, tr("10km"));
    download_distanceCombo->addItem(100, tr("100km"));
    download_distanceCombo->addItem(1000, tr("1000km"));
    download_distanceCombo->selectFirst();

    download_labels.append( new FTLabel("--") );
    download_labels.append( new FTLabel("--") );
    download_labels.append( new FTLabel("--") );
    download_labels.append( new FTLabel("--") );
    download_labels.append( new FTLabel("--") );

}

void BreadcrumbsSync::buildUpload()
{
    uploadPage = new QWidget();
    pages->addWidget( uploadPage );

    upload_activityLabel = new FTLabel( tr("Select activity:") );

    upload_activityCombo = new FTComboBox();
    connect( upload_activityCombo, SIGNAL(selectedItem(QString)),
             this, SLOT(upload_activitySelected(QString)));

    upload_bundleLabel = new FTLabel( tr("Select bundle:") );

    upload_bundleCombo = new FTComboBox();
    connect( upload_bundleCombo, SIGNAL(selectedItem(QString)),
             this, SLOT(upload_bundleSelected(QString)));

    upload_newBundleButton = new FTPushButton( tr("Create new bundle...") );
    connect( upload_newBundleButton, SIGNAL(clicked()),
             this, SLOT(upload_createNewBundle()));

    uploadButton = new FTPushButton( tr("Upload track!") );
    uploadButton->setEnabled( false );
    connect( uploadButton, SIGNAL(clicked()),
             this, SLOT(uploadTrack()) );

    upload_reloadButton = new FTPushButton( tr("Reload activities...") );
    connect( upload_reloadButton, SIGNAL(clicked()),
             this, SLOT(forceReload()) );

    uploadPublicCheck = new FTCheckBox( tr("Track is public") );
    uploadPublicCheck->setChecked(true);
}

void BreadcrumbsSync::forceReload()
{
    loaded = false;
    populateActivities();
}

QString BreadcrumbsSync::selectedActivityId()
{
    QString activity;
    if ( _currentMode == upload_track )
        activity = upload_activityCombo->selectedItem();
    else if ( _currentMode == download_track )
        activity = download_activityCombo->selectedItem();

    if ( list_activities.contains( activity ))
        return list_activities.value( activity );
    else
        return "";
}

QString BreadcrumbsSync::selectedBundleId()
{
    QString activity_id = selectedActivityId();
    if ( activity_id != "" )
    {
        const QMap<QString,QString>& bundles = list_bundles.value( activity_id );
        QString bundle = "";
        if ( _currentMode == upload_track )
            bundle = upload_bundleCombo->selectedItem();
//        else if ( _currentMode == download_track )
//            bundle = download_bundleCombo->selectedItem();

        if ( bundles.contains( bundle ) )
            return bundles.value( bundle );
    }
    return "";
}

void BreadcrumbsSync::update_populateBundles()
{
    QString activity_id = selectedActivityId();
    upload_bundleCombo->clear();

    if ( activity_id == "" )
    {
        upload_bundleCombo->addItem( -1, tr("Please select an activity first" ) );
        uploadButton->setEnabled( false );
        upload_bundleCombo->selectItem( -1 );
    }
    else
    {
        upload_bundleCombo->addItem(-1,  tr("Select a bundle..." ) );
        const QMap<QString,QString>& bundles = list_bundles.value( activity_id );
        foreach (const QString& bundle, bundles.keys() )
            upload_bundleCombo->addItem( bundle );
        upload_bundleCombo->selectItem( -1 );
    }
}

void BreadcrumbsSync::upload_activitySelected(QString)
{
    if ( selectedActivityId() == "" )
        uploadButton->setEnabled( false );
    update_populateBundles();
}

void BreadcrumbsSync::upload_bundleSelected(QString)
{
   if ( selectedBundleId() == "" )
       uploadButton->setEnabled( false );
   else
       uploadButton->setEnabled( true );
}

void BreadcrumbsSync::upload_createNewBundle()
{
    QString activity_id = selectedActivityId();
    if ( activity_id == "" )
        return;

    QString new_bundle = FTMessageBox::TextInput( tr("Create new bundle"),
                                                  tr("Type bundle name:") );

    if ( new_bundle == "" )
        return;

    // Check for duplicates...
    const QMap<QString,QString>& bundles = list_bundles.value( activity_id );
    if ( bundles.contains( new_bundle ) )
    {
        FTMessageBox::Error("Breadcrumbs", tr("Bundle already exist!") );
        return;
    }

    OauthParams params;
    params.insert("name", new_bundle.toAscii().toPercentEncoding() );
    params.insert("activity_id", activity_id.toAscii() );
    oauth->postData("v1/bundles.xml",params,tr("Creating bundle..."));
    if ( !oauth->getError() )
    {
        // Force reloading....
        forceReload();
        upload_activityCombo->selectItem( list_activities.key( activity_id ) );
        update_populateBundles();
        upload_bundleCombo->selectItem( new_bundle );
        if ( selectedBundleId() != "" )
            uploadButton->setEnabled( true );
    }
    else
        FTMessageBox::Error( "Breadcrumbs", tr("Error creating bundle!") );
}

void BreadcrumbsSync::populateActivities()
{
    if (!loaded)
        loadActivities();

    if (loaded)
    {
        upload_activityCombo->clear();
        download_activityCombo->clear();
        download_activityCombo->addItem( -1, tr("Any activity") );
        foreach (const QString& str, list_activities.keys() )
        {
            download_activityCombo->addItem( str );
            upload_activityCombo->addItem( str );
        }
        download_activityCombo->selectFirst();
    }
}

void BreadcrumbsSync::loadActivities()
{
    loaded = false;

    list_activities.clear();
    list_bundles.clear();

    QByteArray rawActivities = oauth->getData("v1/activities.xml",
                                              OauthParams(),
                                              tr("Loading activities..."));

    if ( rawActivities.length() < 1 )
        return;

    QByteArray rawBundles = oauth->getData("v1/bundles.xml",
                                              OauthParams(),
                                              tr("Loading bundles..."));


    QXmlStreamReader stream_a(rawActivities);
    QString id, name;
    bool in_activity = false;

    while (!stream_a.atEnd() && !stream_a.hasError() )
    {
        if ( stream_a.isStartElement() && (stream_a.name() == "activity") )
        {
            id = name = "";
            in_activity = true;
        }
        while ( in_activity && !stream_a.atEnd() && ! stream_a.hasError() )
        {
            stream_a.readNext();
            if ( stream_a.isStartElement() && (stream_a.name() == "id") && (id == "" ) )
            {
                stream_a.readNext();
                id = stream_a.text().toString();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "name") && (name == "" ) )
            {
                stream_a.readNext();
                name = stream_a.text().toString();
            }
            if ( stream_a.isEndElement() && stream_a.name() == "activity" )
            {
                in_activity = false;
                if ( !id.isEmpty() && !name.isEmpty() )
                {
                    list_activities.insert( name, id );
                    list_bundles.insert( id, QMap<QString,QString>() );
                    upload_activityCombo->addItem( name );
                }
            }
        }
        stream_a.readNext();
    }

    QXmlStreamReader stream_b(rawBundles);
    bool in_bundle = false;
    QString id_activity;

    while (!stream_b.atEnd() && !stream_b.hasError() )
    {
        if ( stream_b.isStartElement() && (stream_b.name() == "bundle") )
        {
            id_activity = id = name = "";
            in_bundle = true;
        }
        while ( in_bundle && !stream_b.atEnd() && ! stream_b.hasError() )
        {
            stream_b.readNext();
            if ( stream_b.isStartElement() && (stream_b.name() == "id") && (id == "" ) )
            {
                stream_b.readNext();
                id = stream_b.text().toString();
            }
            if ( stream_b.isStartElement() && (stream_b.name() == "activity-id") && (id_activity == "" ) )
            {
                stream_b.readNext();
                id_activity = stream_b.text().toString();
            }
            if ( stream_b.isStartElement() && (stream_b.name() == "name") && (name == "" ) )
            {
                stream_b.readNext();
                name = stream_b.text().toString();
            }
            if ( stream_b.isEndElement() && stream_b.name() == "bundle" )
            {
                in_bundle = false;
                if ( !id.isEmpty() && !name.isEmpty() && !id_activity.isEmpty() )
                {
                    if ( list_bundles.contains( id_activity ) )
                        list_bundles[id_activity].insert( name, id );
                }
            }
        }
        stream_b.readNext();
    }
    loaded = true;
}

void BreadcrumbsSync::uploadTrack()
{
    QString activity_id = selectedActivityId();
    if ( activity_id == "" )
    {
        FTMessageBox::Error("Breadcrumbs", tr("Please select an activity first!") );
        return;
    }
    QString bundle_id = selectedBundleId();
    if ( bundle_id == "" )
    {
        FTMessageBox::Error("Breadcrumbs", tr("Please select a bundle first!") );
        return;
    }

    OauthParams params;

    params.insert( "import_type", "GPX" );
    params.insert( "bundle_id", bundle_id.toAscii() );
    params.insert( "public", uploadPublicCheck->isChecked() ? "true" : "false" );

    QByteArray xml;
    WorkerSaveGpx worker( xml, track, tr("Converting track..."));
    if ( !worker.run() )
    {
        FTMessageBox::Error( tr("Save error"), tr("Conversion error!") );
        return;
    }

    params.insert("gpx", xml.toPercentEncoding() );
    QByteArray response = oauth->postData("v1/tracks",
                        params,
                        tr("Uploading track..."));

    if ( !oauth->getError() )
    {
        FTMessageBox::Info("Breadcrumbs", tr("Upload successful!") );
        emit trackUploaded();
    }
    else
    {
        FTMessageBox::Error("Breadcrumbs", tr("Unable to upload track: ") + response  );
    }
}

void BreadcrumbsSync::setMode(BreadcrumbsSync::mode md)
{
    bool isAuth = configuration->breadcrumbsAuthorized();

    // Remove auth if not authorized
    if ( !isAuth )
    {
        if ( oauth != NULL )
        {
            delete oauth;
            oauth = NULL;
        }
        pages->setCurrentWidget( notConfiguredLabel );
    }
    // Set auth is authorized
    else if ( isAuth )
    {
        if ( oauth == NULL )
        {
            QByteArray token;
            QByteArray secret;
            configuration->breadcrumbsToken( token, secret );
            oauth = new OauthManager(this, token, secret);
        }
        if ( _currentMode == md)
            return;
        if ( _currentMode == not_initialized )
            populateActivities();
        _currentMode = md;
        if ( _currentMode == BreadcrumbsSync::upload_track )
            pages->setCurrentWidget( uploadPage );
        else if ( _currentMode == BreadcrumbsSync::download_track )
            pages->setCurrentWidget( downloadPage );
    }
}

void BreadcrumbsSync::setUploadTrack(const GPS_track* ut)
{
    track = ut;
    setMode( BreadcrumbsSync::upload_track );
}

void BreadcrumbsSync::download_searchTracks()
{
    int distance = download_distanceCombo->selectedItemId();
    int numTracks = download_numTracksCombo->selectedItemId();
    QString activity_id = selectedActivityId();
    double lat, lon;
    int alt;
    configuration->initialPosition( lat, lon, alt );

    OauthParams params;
    params.insert( "lat", QString("%1").arg(lat, 0, 'f').toAscii() );
    params.insert( "lng", QString("%1").arg(lon, 0, 'f').toAscii() );
    params.insert( "distance", QString("%1").arg(distance).toAscii() );
    if ( activity_id != "" )
        params.insert( "activity_id", activity_id.toAscii() );
    params.insert( "page", "1" );
    params.insert( "per_page", QString("%1").arg(numTracks).toAscii() );

    QByteArray rawTracks = oauth->getData("v1/search.xml",
                                          params,
                                          tr("Searching tracks..."));

    download_fetchedCombo->clear();
    foreach (searched_track* trk, download_fetched)
        delete trk;
    download_fetched.clear();

    QXmlStreamReader stream_a(rawTracks);
    bool in_track = false;
    searched_track* track = NULL;

    while (!stream_a.atEnd() && !stream_a.hasError() )
    {
        if ( stream_a.isStartElement() && (stream_a.name() == "track") )
        {
            track = new searched_track;
            track->description = track->name = track->id = "";
            track->lat = track->lon = track->elevation_gain = track->distance = 0.0;
            track->difficulty = track->track_rating = 0;
            track->start_time = track->end_time = QDateTime();
            in_track = true;
        }
        while ( in_track && !stream_a.atEnd() && ! stream_a.hasError() )
        {
            stream_a.readNext();
            if ( stream_a.isStartElement() && (stream_a.name() == "id") )
            {
                stream_a.readNext();
                track->id = stream_a.text().toString();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "name") )
            {
                stream_a.readNext();
                track->name = stream_a.text().toString();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "description") )
            {
                stream_a.readNext();
                track->description = stream_a.text().toString();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "lat") )
            {
                stream_a.readNext();
                track->lat = stream_a.text().toString().toDouble();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "lng") )
            {
                stream_a.readNext();
                track->lon = stream_a.text().toString().toDouble();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "elevation-gain") )
            {
                stream_a.readNext();
                track->elevation_gain = stream_a.text().toString().toDouble();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "total-distance") )
            {
                stream_a.readNext();
                track->distance = stream_a.text().toString().toDouble();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "difficulty") )
            {
                stream_a.readNext();
                track->difficulty = stream_a.text().toString().toInt();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "track-rating") )
            {
                stream_a.readNext();
                track->track_rating = stream_a.text().toString().toInt();
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "start-time") )
            {
                stream_a.readNext();
                track->start_time = QDateTime::fromString( stream_a.text().toString(), Qt::ISODate );
            }
            if ( stream_a.isStartElement() && (stream_a.name() == "end-time") )
            {
                stream_a.readNext();
                track->end_time = QDateTime::fromString( stream_a.text().toString(), Qt::ISODate );
            }

            if ( stream_a.isEndElement() && stream_a.name() == "track" )
            {
                in_track = false;
                if ( !track->id.isEmpty() && !track->name.isEmpty() )
                {
                    download_fetched.append( track );
                    download_fetchedCombo->addItem( download_fetched.indexOf( track ), track->name );
                    track = NULL;
                }
            }
        }
        stream_a.readNext();
    }
    if ( track != NULL )
        delete track;
    if ( download_fetched.count() > 0 )
    {
        download_fetchedCombo->selectFirst();
    }
    else
    {
        download_fetchedCombo->addItem(-1, tr("No tracks found!") );
    }
    download_populateFetched();
}

searched_track* BreadcrumbsSync::download_selectedTrack()
{
    int fetched_id = download_fetchedCombo->selectedItemId();
    if ( (fetched_id > -1) && ( fetched_id < download_fetched.count() ) )
        return download_fetched.at( fetched_id );
    return NULL;
}

void BreadcrumbsSync::download_populateFetched()
{
    searched_track* track = download_selectedTrack();
    if ( track != NULL )
    {
        // Label_0: <name>
        // Label_1: <start-time> + <end-time>
        // Label_2: <total-distance> <elevation-gain>
        // Label_3: <lat>, <lng>
        // Label_4: <difficulty> <track-rating>
        download_labels[0]->setText( track->name );
        if ( track->start_time.isValid() || track->end_time.isValid() )
            download_labels[1]->setText( track->start_time.toString("dd/MM/yy, hh:mm.ss") + " - " +
                                         track->end_time.toString("dd/MM/yy, hh:mm.ss") );
        else
            download_labels[1]->setText( tr("no time specified") );

        download_labels[2]->setText( QString("%1km / %2mt").arg(track->distance/1000.0, 0, 'f', 2)
                                                           .arg(track->elevation_gain, 0, 'f', 0));
        if ( track->description != "" )
            download_labels[3]->setText( track->description );
        else
            download_labels[3]->setText( tr("(no description)" ) );
        download_labels[4]->setText( QString("%1 - %1").arg(track->difficulty).arg(track->track_rating));
        download_fetchButton->setEnabled( true );
    }
    else
    {
        foreach (FTLabel* label, download_labels)
            label->setText("--");
        download_fetchButton->setEnabled( false );
    }
}

void BreadcrumbsSync::download_fetchTrack()
{
    searched_track* track = download_selectedTrack();
    QString url = "v1/tracks/"+track->id+"/placemarks.gpx";

    QByteArray rawTrack = oauth->getData(url,
                                          OauthParams(),
                                          tr("Downloading track..."));

    if ( !oauth->getError() )
    {
        FTMessageBox::Info("Breadcrumbs", tr("Track downloaded!") );
        downloadedTrack = new GPS_track();

        // create the worker...
        WorkerLoadGpx runner( rawTrack, downloadedTrack, tr("Loading GPX...") );
        // Load the GPX!
        if ( !runner.run() )
        {
            FTMessageBox::Error(tr("Loading track..."), tr("Invalid GPS track!"));
            delete downloadedTrack;
        }
        else
        {
            if ( FTMessageBox::Yesno( tr("Loading track..."), tr("Save the track to disk?") ) )
            {
                QStringList filters;
                filters << "*gpx";
                QString filename = FileBrowser::browseFilename(FileBrowser::saveMode,
                                                               tr("Save track"),
                                                               configuration->defaultPath(),
                                                               filters);
                if ( ( filename != "") && !filename.endsWith(".gpx") )
                    filename += ".gpx";

                if ( filename != "" )
                {
                    QFile file(filename);
                    if ( file.open(QIODevice::WriteOnly ) )
                    {
                        file.write( rawTrack );
                        file.close();
                        FTMessageBox::Info( tr("Saving track..."), tr("Track saved!" ) );
                    }
                    else
                        FTMessageBox::Error(tr("Saving track..."), tr("Unable to save track!" ) );
                }
            }
            emit trackDownloaded();
        }
    }
    else
    {
        FTMessageBox::Error("Breadcrumbs", tr("Unable to download track: ") + rawTrack  );
    }
}

void BreadcrumbsSync::download_displayTrack()
{
    download_populateFetched();
}

QLayout* BreadcrumbsSync::createVertical()
{
    FTVBoxLayout* grid;
    FTVBoxLayout* vgrid;
    FTHBoxLayout* hgrid;

    if ( uploadPage->layout() != NULL )
        delete uploadPage->layout();
    grid = new FTVBoxLayout();
    grid->addWidget( upload_reloadButton );
    grid->addWidget( upload_activityLabel );
    grid->addWidget( upload_activityCombo );
    grid->addWidget( upload_bundleLabel );
    grid->addWidget( upload_bundleCombo );
    grid->addWidget( uploadPublicCheck );
    grid->addWidget( upload_newBundleButton);
    grid->addStretch();
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( uploadButton );
    grid->addLayout( hgrid );
    grid->addStretch();
    uploadPage->setLayout( grid );

    if ( downloadPage->layout() != NULL )
        delete downloadPage->layout();
    grid = new FTVBoxLayout();
    grid->addWidget( download_activityLabel );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget(download_reloadButton );
    hgrid->addWidget(download_activityCombo );
    grid->addLayout( hgrid );
    hgrid = new FTHBoxLayout();
    vgrid = new FTVBoxLayout();
    vgrid->addWidget( download_numTracksLabel );
    vgrid->addWidget( download_numTracksCombo );
    hgrid->addLayout(vgrid);
    vgrid = new FTVBoxLayout();
    vgrid->addWidget( download_distanceLabel );
    vgrid->addWidget( download_distanceCombo );
    hgrid->addLayout(vgrid);
    grid->addLayout( hgrid );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget(download_searchButton);
    grid->addLayout( hgrid );
    grid->addWidget(download_fetchedCombo);
    foreach (FTLabel* labels, download_labels)
        grid->addWidget( labels );
    grid->addWidget(download_fetchButton);
    downloadPage->setLayout( grid );

    grid = new FTVBoxLayout();
    grid->addWidget( pages );
    return grid;
}

QLayout* BreadcrumbsSync::createHorizontal()
{
    FTVBoxLayout* grid;
    FTVBoxLayout* vgrid;
    FTHBoxLayout* hgrid;

    if ( uploadPage->layout() != NULL )
        delete uploadPage->layout();
    grid = new FTVBoxLayout();
    grid->addWidget( upload_reloadButton );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( upload_activityLabel );
    hgrid->addWidget( upload_activityCombo );
    grid->addLayout( hgrid );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( upload_bundleLabel );
    hgrid->addWidget( upload_bundleCombo );
    grid->addLayout( hgrid );
    grid->addWidget( upload_newBundleButton);
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( uploadPublicCheck );
    hgrid->addWidget( uploadButton );
    grid->addLayout( hgrid );
    grid->addStretch();
    uploadPage->setLayout( grid );

    if ( downloadPage->layout() != NULL )
        delete downloadPage->layout();
    grid = new FTVBoxLayout();
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( download_activityLabel );
    hgrid->addWidget(download_reloadButton );
    hgrid->addWidget(download_activityCombo, 2 );
    grid->addLayout( hgrid );
    hgrid = new FTHBoxLayout();
    vgrid = new FTVBoxLayout();
    vgrid->addWidget( download_numTracksLabel );
    vgrid->addWidget( download_numTracksCombo );
    hgrid->addLayout(vgrid);
    vgrid = new FTVBoxLayout();
    vgrid->addWidget( download_distanceLabel );
    vgrid->addWidget( download_distanceCombo );
    hgrid->addLayout(vgrid);
    grid->addLayout( hgrid );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget(download_searchButton);
    hgrid->addWidget(download_fetchedCombo, 2);
    grid->addLayout( hgrid );

    hgrid = new FTHBoxLayout();
    int n = 0;
    foreach (FTLabel* labels, download_labels)
    {
        hgrid->addWidget( labels );
        if ( n == 1 )
        {
            n = 0;
            grid->addLayout( hgrid );
            hgrid = new FTHBoxLayout();
        }
        else
            n++;
    }
    if ( n == 1 )
        grid->addLayout( hgrid );

    grid->addWidget(download_fetchButton);
    grid->addStretch();
    downloadPage->setLayout( grid );

    grid = new FTVBoxLayout();
    grid->addWidget( pages );
    return grid;
}
